package com.xxl.job.executor.common.util.http;

import com.alibaba.fastjson.JSONObject;
import com.xxl.job.executor.common.util.Constants;
import com.xxl.job.executor.common.util.DateTimeUtil;
import com.xxl.job.executor.pojo.ResponseEntity;
import com.xxl.job.executor.pojo.TbMsgSendLog;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.http.Consts;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.FileBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;

import java.io.*;
import java.net.SocketTimeoutException;
import java.util.HashMap;
import java.util.Map;

/**
 * @description：
 * @author: PanNaiZhao
 * @DATE: 2017-06-01 9:23
 * @projectName: DataExchangeSystem
 */
public class HttpsUtilWithPool {
    private static Log logger = LogFactory.getLog(HttpsUtilWithPool.class);

    /**
     * 无需本地证书keyStore的SSL https带参数请求
     * post K - V 格式的数据
     * @param url
     * @param
     * @param
     * @return
     */
    public static TbMsgSendLog httpsPostBinary(String url, String binfileMd5, String binfileGzip,
                                               String binfileAuth, String jsonStr, String fileName, HttpsInitManager manager) {

        if (manager.isNeedHttpsPool()) {
            return httpsPostBinaryByPool(url,binfileMd5,binfileGzip,
                    binfileAuth,jsonStr,fileName,manager);
        }
        TbMsgSendLog tbMsgSendLog = new TbMsgSendLog();
        tbMsgSendLog.setSendTime(DateTimeUtil.getNowTimestamp());
        tbMsgSendLog.setCreateTime(DateTimeUtil.getNowTimestamp());
        if ("true".equals(binfileGzip)) {
            tbMsgSendLog.setIsSendZip(1);
        } else {
            tbMsgSendLog.setIsSendZip(0);
        }

        //创建一个信任的连接
        CloseableHttpClient httpClient = manager.getHttpsClient();
        //发送请求的实体类
        HttpPost httpPost = new HttpPost(url);
        //接收返回值
        StringBuilder sb = new StringBuilder();
        BufferedReader br = null;
        JSONObject jsonObject = null;
        InputStreamReader in = null;
        CloseableHttpResponse response = null;

        try {
            //设置请求头（headers)
            httpPost.setHeader("binfile-md5", binfileMd5);
            httpPost.setHeader("binfile-gzip", binfileGzip);
            httpPost.setHeader("binfile-auth", binfileAuth);

            StringBody fileNameRes = new StringBody(fileName, ContentType.create(
                            "text/plain", Consts.UTF_8));

            //设置请求内容（content)
            HttpEntity reqEntity = MultipartEntityBuilder.create()
                    .addBinaryBody("binFile", jsonStr.getBytes(Consts.UTF_8), ContentType.APPLICATION_OCTET_STREAM,fileName)
                    .addPart("filename", fileNameRes)
                    .build();

            httpPost.setEntity(reqEntity);

            // 设置客户端请求的头参数getParams已经过时,现在用requestConfig对象替换
//            httpPost.setConfig(getRequestConfig(httpsConfig));

//            httpClient.
            //发送请求,如果当前的这个httpClient过期了会从新生成一个（测试得出)
            response = httpClient.execute(httpPost);

            //接收响应头信息
            Header[] resp_headers = response.getAllHeaders();

            Map<String, String> headerMap = new HashMap<String, String>();
            for (Header header : resp_headers) {
                headerMap.put(header.getName(), header.getValue());
            }
            tbMsgSendLog.setSendResultCode(response.getStatusLine().getStatusCode());
            tbMsgSendLog.setRespMd5(headerMap.get("binfile-md5"));
            tbMsgSendLog.setContentDisposition(headerMap.get("Content-Disposition"));
            tbMsgSendLog.setContentEncoding(headerMap.get("Content-Encoding"));
            tbMsgSendLog.setContentLength(headerMap.get("Content-Length"));
            try {
                int beginIndex = tbMsgSendLog.getContentDisposition().indexOf("=");
                String resultFileName = tbMsgSendLog.getContentDisposition().substring(beginIndex + 1).replace("\"", "");
                tbMsgSendLog.setRespFileName(resultFileName);
            } catch (Exception e) {
                logger.info("获取不到响应的文件名");
                if(tbMsgSendLog.getSendResultCode()==null) {
                	tbMsgSendLog.setSendResultCode(Constants.ErrorType.NOTFILE_ERR.getValue());
                }
                tbMsgSendLog.setRespFileName(null);
            }

            //接收响应返回值
            HttpEntity httpEntity = response.getEntity();

            //返回值处理
            in = new InputStreamReader(httpEntity.getContent(), Consts.UTF_8);
            br = new BufferedReader(in);
            String s = null;
            while ((s = br.readLine()) != null) {
                sb.append(s);
            }
            //结算中心返回消息处理
            respInfoHandle(sb,tbMsgSendLog,fileName);
           
        } catch (UnsupportedEncodingException e) {
            logger.error("指定的编码集不对,您目前指定的编码集是:" + Consts.UTF_8, e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.ENCODING_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } catch (ClientProtocolException e) {
            logger.error("客户端异常", e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.CLIENT_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } catch (SocketTimeoutException e) {
            logger.error("SocketTimeoutException异常", e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.SOCKET_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("网络异常" + e.getClass().getSimpleName());
        } catch (IOException e) {
            logger.error("IO异常", e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.IO_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } catch (Exception e) {
            logger.error("通讯未知系统异常", e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.COMM_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    logger.error("读取https响应关闭br流出错！", e);
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error("读取https响应关闭in流出错！", e);
                }
            }
            if(response != null){
                try {
                    response.close();
                } catch (IOException e) {
                    logger.error("读取https响应关闭response出错！", e);
                }
            }
            httpPost.abort();
            if (httpClient != null) {
                try {
                    httpClient.close();
                } catch (IOException e) {
                    logger.error("httpClient关闭出错！", e);
                }
            }
        }
        return tbMsgSendLog;
    }

    public static TbMsgSendLog httpsPostFileBinary(String url, String binfileMd5, String binfileGzip,
                                               String binfileAuth, File jsonFile, HttpsInitManager manager) {

//        if (manager.isNeedHttpsPool()) {
            return httpsPostFileBinaryByPool(url,binfileMd5,binfileGzip,
                    binfileAuth,jsonFile,manager);
//        }


    }

    public static TbMsgSendLog httpsPostBinaryByPool(String url, String binfileMd5, String binfileGzip,
                                               String binfileAuth, String jsonStr, String fileName, HttpsInitManager manager) {
        TbMsgSendLog tbMsgSendLog = new TbMsgSendLog();
        tbMsgSendLog.setSendTime(DateTimeUtil.getNowTimestamp());
        tbMsgSendLog.setCreateTime(DateTimeUtil.getNowTimestamp());
        if ("true".equals(binfileGzip)) {
            tbMsgSendLog.setIsSendZip(1);
        } else {
            tbMsgSendLog.setIsSendZip(0);
        }
        CloseableHttpClient httpClient;
        if (manager.isSingleClient()) {
            httpClient = manager.getHttpsClientByPoolNew();
        }else {
            //创建一个信任的连接
            httpClient = manager.getHttpsClientByPool();
        }
        //发送请求的实体类
        HttpPost httpPost = new HttpPost(url);
        //接收返回值
        StringBuilder sb = new StringBuilder();
        BufferedReader br = null;
        InputStreamReader in = null;
        JSONObject jsonObject = null;
        CloseableHttpResponse response = null;

        try {
            //设置请求头（headers)
            httpPost.setHeader("binfile-md5", binfileMd5);
            httpPost.setHeader("binfile-gzip", binfileGzip);
            httpPost.setHeader("binfile-auth", binfileAuth);

            StringBody fileNameRes = new StringBody(fileName, ContentType.create(
                    "text/plain", Consts.UTF_8));

            //设置请求内容（content)
            HttpEntity reqEntity = MultipartEntityBuilder.create()
                    .addBinaryBody("binFile", jsonStr.getBytes(Consts.UTF_8), ContentType.APPLICATION_OCTET_STREAM,fileName)
                    .addPart("filename", fileNameRes)
                    .build();

            httpPost.setEntity(reqEntity);

            // 设置客户端请求的头参数getParams已经过时,现在用requestConfig对象替换
//            httpPost.setConfig(getRequestConfig(httpsConfig));

//            httpClient.
            //发送请求,如果当前的这个httpClient过期了会从新生成一个（测试得出)
            response = httpClient.execute(httpPost);

            //接收响应头信息
            Header[] resp_headers = response.getAllHeaders();

            Map<String, String> headerMap = new HashMap<String, String>();
            for (Header header : resp_headers) {
                headerMap.put(header.getName(), header.getValue());
            }
            tbMsgSendLog.setSendResultCode(response.getStatusLine().getStatusCode());
            tbMsgSendLog.setRespMd5(headerMap.get("binfile-md5"));
            tbMsgSendLog.setContentDisposition(headerMap.get("Content-Disposition"));
            tbMsgSendLog.setContentEncoding(headerMap.get("Content-Encoding"));
            tbMsgSendLog.setContentLength(headerMap.get("Content-Length"));
            try {
            	if(tbMsgSendLog.getContentDisposition()!=null && tbMsgSendLog.getContentDisposition().indexOf("=")>0) {
	                int beginIndex = tbMsgSendLog.getContentDisposition().indexOf("=");
	                String resultFileName = tbMsgSendLog.getContentDisposition().substring(beginIndex + 1).replace("\"", "");
	                tbMsgSendLog.setRespFileName(resultFileName);
            	}
            } catch (Exception e) {
                logger.info("获取不到响应的文件名");
                if(tbMsgSendLog.getSendResultCode()==null) {
                	tbMsgSendLog.setSendResultCode(Constants.ErrorType.NOTFILE_ERR.getValue());
                }
                tbMsgSendLog.setRespFileName(null);
            }

            //接收响应返回值
            HttpEntity httpEntity = response.getEntity();

            //返回值处理
            in = new InputStreamReader(httpEntity.getContent(), Consts.UTF_8);
            br = new BufferedReader(in);
            String s = null;
            while ((s = br.readLine()) != null) {
                sb.append(s);
            }

            //结算中心返回消息处理
            respInfoHandle(sb,tbMsgSendLog,fileName);
                

        } catch (UnsupportedEncodingException e) {
            logger.error("指定的编码集不对,您目前指定的编码集是:" + Consts.UTF_8, e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.ENCODING_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } catch (ClientProtocolException e) {
            logger.error("客户端异常", e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.CLIENT_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } catch (IOException e) {
            logger.error("IO异常", e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.IO_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } catch (Exception e) {
            logger.error("通讯未知系统异常", e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.COMM_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    logger.error("读取https响应关闭br流出错！", e);
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error("读取https响应关闭in流出错！", e);
                }
            }
            if(response != null){
                try {
                    response.close();
                } catch (IOException e) {
                    logger.error("读取https响应关闭response出错！", e);
                }
            }
        }
        return tbMsgSendLog;
    }
    
  

    public static TbMsgSendLog httpsPostFileBinaryByPool(String url, String binfileMd5, String binfileGzip,
                                                   String binfileAuth, File jsonFile, HttpsInitManager manager) {

        TbMsgSendLog tbMsgSendLog = new TbMsgSendLog();
        tbMsgSendLog.setSendTime(DateTimeUtil.getNowTimestamp());
        tbMsgSendLog.setCreateTime(DateTimeUtil.getNowTimestamp());
        if ("true".equals(binfileGzip)) {
            tbMsgSendLog.setIsSendZip(1);
        } else {
            tbMsgSendLog.setIsSendZip(0);
        }

        CloseableHttpClient httpClient;
        if (manager.isSingleClient()) {
            httpClient = manager.getHttpsClientByPoolNew();
        }else {
            //创建一个信任的连接
            httpClient = manager.getHttpsClientByPool();
        }
        //发送请求的实体类
        HttpPost httpPost = new HttpPost(url);
        //接收返回值
        StringBuilder sb = new StringBuilder();
        BufferedReader br = null;
        JSONObject jsonObject = null;
        CloseableHttpResponse response = null;
        InputStreamReader in = null;

        try {
            //设置请求头（headers)
            httpPost.setHeader("binfile-md5", binfileMd5);
            httpPost.setHeader("binfile-gzip", binfileGzip);
            httpPost.setHeader("binfile-auth", binfileAuth);

            // 把文件转换成流对象FileBody
            FileBody binJsonFile = new FileBody(jsonFile);
            String fileName = jsonFile.getName();

            StringBody fileNameRes = new StringBody(fileName, ContentType.create(
                    "text/plain", Consts.UTF_8));

            //设置请求内容（content)
            HttpEntity reqEntity = MultipartEntityBuilder.create()
                    .addPart("binFile", binJsonFile)
                    .addPart("filename", fileNameRes)
                    .build();

            httpPost.setEntity(reqEntity);

            // 设置客户端请求的头参数getParams已经过时,现在用requestConfig对象替换
//            httpPost.setConfig(getRequestConfig(httpsConfig));

//            httpClient.
            //发送请求
            response = httpClient.execute(httpPost);

            //接收响应头信息
            Header[] resp_headers = response.getAllHeaders();

            Map<String, String> headerMap = new HashMap<String, String>();
            for (Header header : resp_headers) {
                headerMap.put(header.getName(), header.getValue());
            }
//            Integer statusCode = Integer.parseInt(headerMap.get("Status-Code"));
            tbMsgSendLog.setSendResultCode(response.getStatusLine().getStatusCode());
            tbMsgSendLog.setRespMd5(headerMap.get("binfile-md5"));
            tbMsgSendLog.setContentDisposition(headerMap.get("Content-Disposition"));
            tbMsgSendLog.setContentEncoding(headerMap.get("Content-Encoding"));
            tbMsgSendLog.setContentLength(headerMap.get("Content-Length"));
            try {
                int beginIndex = tbMsgSendLog.getContentDisposition().indexOf("=");
                String resultFileName = tbMsgSendLog.getContentDisposition().substring(beginIndex + 1).replace("\"", "");
                tbMsgSendLog.setRespFileName(resultFileName);
            } catch (Exception e) {
                logger.info("获取不到响应的文件名");
                if(tbMsgSendLog.getSendResultCode()==null) {
                	tbMsgSendLog.setSendResultCode(Constants.ErrorType.NOTFILE_ERR.getValue());
                }
                tbMsgSendLog.setRespFileName(null);
            }

            //接收响应返回值
            HttpEntity httpEntity = response.getEntity();

            //返回值处理
            in = new InputStreamReader(httpEntity.getContent(), Consts.UTF_8);
            br = new BufferedReader(in);
            String s = null;
            while ((s = br.readLine()) != null) {
                sb.append(s);
            }

            //结算中心返回消息处理
            respInfoHandle(sb,tbMsgSendLog,fileName);
                
           

        } catch (UnsupportedEncodingException e) {
            logger.error("指定的编码集不对,您目前指定的编码集是:" + Consts.UTF_8, e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.ENCODING_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } catch (ClientProtocolException e) {
            logger.error("客户端异常", e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.CLIENT_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } catch (IOException e) {
            logger.error("IO异常", e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.IO_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } catch (Exception e) {
            logger.error("通讯未知系统异常", e);
            tbMsgSendLog.setSendResultCode(Constants.ErrorType.COMM_ERR.getValue());
            tbMsgSendLog.setSendResultDesc("本地程序异常" + e.getClass().getSimpleName());
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    logger.error("读取https响应关闭br流出错！", e);
                }
            }
            if (in != null) {
                try {
                    in.close();
                } catch (IOException e) {
                    logger.error("读取https响应关闭in流出错！", e);
                }
            }
            if(response != null){
                try {
                    response.close();
                } catch (IOException e) {
                    logger.error("读取https响应关闭response出错！", e);
                }
            }
        }
        return tbMsgSendLog;
    }

    //结算中心返回消息处理
    private  static void respInfoHandle(StringBuilder sb,  TbMsgSendLog tbMsgSendLog ,String fileName){
    	
    	//如果返回的不是200,那么打印全部日志
    	 if (tbMsgSendLog.getSendResultCode() != null && tbMsgSendLog.getSendResultCode() != 200) {
            
         	  logger.info("结算中心返回错误码："+tbMsgSendLog.getSendResultCode()+",请求的文件路径为："+fileName+",返回的错误消息为："+sb.toString());
         }
    	 try {
    		 ResponseEntity responseEntity = JSONObject.parseObject(sb.toString(),ResponseEntity.class);
             tbMsgSendLog.setResponseEntity(responseEntity);
             tbMsgSendLog.setSendResultRecvTime(DateTimeUtil.getNowTimestamp());
         } catch (Exception e) {
             logger.info("响应的不是Json，而是字符串:" + sb.toString());
             String desc = sb.toString();
             if (desc.length() > 4000) {
                 desc = desc.substring(0, 4000);
             }
             tbMsgSendLog.setSendResultDesc(desc);
             tbMsgSendLog.setSendResultRecvTime(DateTimeUtil.getNowTimestamp());
         }
         tbMsgSendLog.setResultJson(sb.toString());
    }
}
